﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using UnityEngine;
namespace ChenYiZh
{
    public class UDPNetwork
    {
        private static Queue<byte[]> SendMsgs;
        private static UdpClient SendClient;
        private static UdpClient ReceiveClient;
        private static Coroutine SendThread;
        private static Coroutine ReceiveThread;
        public static Networking Networking
        {
            private set;
            get;
        }
        public static ushort SEND_PORT
        {
            private set;
            get;
        }
        public static ushort RECEIVE_PORT
        {
            private set;
            get;
        }
        public static void Init(ushort sendPort, ushort receivePort, Networking networking, bool begin = true)
        {
            Close();
            Networking = networking;
            SEND_PORT = sendPort;
            RECEIVE_PORT = receivePort;
            SendMsgs = new Queue<byte[]>();
            try
            {
                SendClient = new UdpClient(new IPEndPoint(IPAddress.Any, SEND_PORT));
                SendClient.EnableBroadcast = true;
                SendClient.Connect(IPAddress.Broadcast, RECEIVE_PORT);
                ReceiveClient = new UdpClient(new IPEndPoint(IPAddress.Any, RECEIVE_PORT));
                ReceiveClient.EnableBroadcast = true;
                if (begin)
                    Begin();
            }
            catch (Exception e)
            {
                Debug.LogError(e);
            }
        }
        public static void Begin()
        {
            SendThread = Networking.StartCoroutine(SendCoroutine());
            ReceiveThread = Networking.StartCoroutine(ReceiveCoroutine());
        }

        public static void Send(byte[] data)
        {
            if (SendThread == null || ReceiveThread == null)
                Debug.LogWarning("UDPClient hasn't begun");
            SendMsgs.Enqueue(data);
        }

        private static IEnumerator SendCoroutine()
        {
            while (true)
            {
                if (SendMsgs.Count > 0)
                {
                    byte[] sendData = SendMsgs.Dequeue();
                    IAsyncResult result = SendClient.BeginSend(sendData, sendData.Length, null, null);
                    while (!result.IsCompleted)
                        yield return null;
                    SendClient.EndSend(result);
                }
                yield return null;
            }
        }

        private static IEnumerator ReceiveCoroutine()
        {
            while (true)
            {
                IAsyncResult result = ReceiveClient.BeginReceive(null, null);
                while (!result.IsCompleted)
                    yield return null;
                IPEndPoint ep = null;
                byte[] data = ReceiveClient.EndReceive(result, ref ep);
                Networking.ReceiveHandler(data);
            }
        }

        public static void Close()
        {
            if (SendThread != null && Networking != null)
                Networking.StopCoroutine(SendThread);
            if (ReceiveThread != null && Networking != null)
                Networking.StopCoroutine(ReceiveThread);
            SendThread = ReceiveThread = null;
            if (SendClient != null)
            { try { SendClient.Close(); } catch (Exception e) { Debug.LogWarning(e.Message); } }
            if (ReceiveClient != null)
            { try { ReceiveClient.Close(); } catch (Exception e) { Debug.LogWarning(e.Message); } }
        }
    }
}
